#pragma once
#include "StdAfx.h"
#include "graphics/GrVector.h"
#include "SgComposite.h"
#include "SgRegularPolygon.h"
#include "SgQuad.h"
#include "SgRegularCylinder.h"
#include "SgTranslate.h"
#include "SgRotateAroundPoint.h"


#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

inline void Normalize(GLdouble *v)
{
    GLdouble len = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
    v[0] /= len;
    v[1] /= len;
    v[2] /= len;
}

CSgRegularCylinder::CSgRegularCylinder(void)
: m_mapping(0)
{
}

CSgRegularCylinder::~CSgRegularCylinder(void)
{
}
void CSgRegularCylinder::SetProperties(int numOfSides,double height, double radius)
{
	m_numOfSides = numOfSides;
	m_Height = height;
	m_Radius = radius;
}

void CSgRegularCylinder::Render(void){
	
	CSgPtr<CSgComposite> regularCylindar = new CSgComposite();

	CSgPtr<CSgRegularPolygon> bottom = new CSgRegularPolygon();
	bottom->SetProperties(m_numOfSides,m_Radius);
	GLdouble bottomNormal[] = {0.0,-1.0,0.0};
	bottom->SetNormal(bottomNormal);
	regularCylindar->AddChild(bottom);//adds "bottom"

	CSgPtr<CSgRegularPolygon> top = new CSgRegularPolygon();
	top->SetProperties(m_numOfSides,m_Radius);
	GLdouble topNormal[] = {0.0,-1.0,0.0};
	top->SetNormal(topNormal);

	CSgPtr<CSgRotateAroundPoint> topRotation = new CSgRotateAroundPoint();
	topRotation->SetPoint(0.0,0.0,0.0);
	topRotation->SetAngle(180);
	topRotation->SetNormal(1.0,0.0,0.0);
	topRotation->AddChild(top);

	CSgPtr<CSgTranslate> topMove = new CSgTranslate();
	topMove->SetProperties(0.0,m_Height,0.0);
	topMove->AddChild(topRotation);
	

	regularCylindar->AddChild(topMove);//adds the top

	//d-c
	//| |
	//a_b
	for (double i = 0; i < m_numOfSides; i++)
	{
		std::vector< std::vector<GLfloat> > texCoords(4);
		GLdouble a[] = {m_Radius*cos((i+1)*2*M_PI/m_numOfSides+2*M_PI/(m_numOfSides*2.0)),0.0,m_Radius*sin((i+1)*2*M_PI/m_numOfSides+2*M_PI/(m_numOfSides*2.0))};
		if(m_mapping==0){
		texCoords[0].push_back(0.0);
		texCoords[0].push_back(GLfloat((a[0]/m_Radius+1)/2));
		}
		if(m_mapping==1){
			texCoords[0].push_back(0.0);
			texCoords[0].push_back(0.0);
		}
		
		//texCoords[0].push_back(GLfloat(a[0]/m_Radius));
		GLdouble b[] = {m_Radius*cos(i*2*M_PI/m_numOfSides+2*M_PI/(m_numOfSides*2.0)),0.0,m_Radius*sin(i*2*M_PI/m_numOfSides+2*M_PI/(m_numOfSides*2.0))};
		if(m_mapping==0){
		texCoords[1].push_back(0.0);
		texCoords[1].push_back(GLfloat((b[0]/m_Radius+1)/2));
		}
		if(m_mapping==1){
		texCoords[1].push_back(1.0);
		texCoords[1].push_back(0.0);
		}
		//texCoords[1].push_back(GLfloat(b[0]/m_Radius));
		GLdouble c[] = {m_Radius*cos(i*2*M_PI/m_numOfSides+2*M_PI/(m_numOfSides*2.0)),m_Height,m_Radius*sin(i*2*M_PI/m_numOfSides+2*M_PI/(m_numOfSides*2.0))};
		if(m_mapping==0){
		texCoords[2].push_back(1.0);
		texCoords[2].push_back(GLfloat((c[0]/m_Radius+1)/2));
		}

		if(m_mapping==1){
		texCoords[2].push_back(1.0);
		texCoords[2].push_back(1.0);
		}
		//texCoords[2].push_back(GLfloat(c[0]/m_Radius));
		GLdouble d[] = {m_Radius*cos((i+1)*2*M_PI/m_numOfSides+2*M_PI/(m_numOfSides*2.0)),m_Height,m_Radius*sin((i+1)*2*M_PI/m_numOfSides+2*M_PI/(m_numOfSides*2.0))};
		if(m_mapping==0){
		texCoords[3].push_back(1.0);
		texCoords[3].push_back(GLfloat((d[0]/m_Radius+1)/2));
		}
		if(m_mapping==1){
		texCoords[3].push_back(0.0);
		texCoords[3].push_back(1.0);
		}
		//texCoords[3].push_back(GLfloat(d[0]/m_Radius));
		
		CSgPtr<CSgQuad> newQuad = new CSgQuad();
		newQuad->SetProperties(a,b,c,d);
		newQuad->SetTex(texCoords);
		// Normalized avg between top 2 (or bottom 2) coordinates, no y coordinate)
		GLdouble normal[] = {(d[0] + c[0]) / 2.0, 0, (d[2] + c[2]) / 2.0};
		Normalize(normal);
		newQuad->SetNormal(normal);
		regularCylindar->AddChild(newQuad);
	}
	regularCylindar->Render();
}
void CSgRegularCylinder::SetMapping(int mapping)
{
	m_mapping=mapping;
}
